
#include "tools/variant.h"

#if 0

template<class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator {
    typedef T value_type;
    typedef Distance difference_type;
    typedef Pointer pointer;
    typedef Reference reference;
    typedef Category iterator_category;
};
As you can see, the defaults are:

typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;


#endif


namespace tools{

    using namespace variant_detail;

    namespace {
        typedef Variant::iterator
            iterator;
        typedef Variant::const_iterator
            const_iterator;
        typedef Variant::reverse_iterator
            reverse_iterator;
        typedef Variant::const_reverse_iterator
            const_reverse_iterator;
        typedef Variant::const_recursive_iterator
            const_recursive_iterator;
        typedef Variant::recursive_iterator
            recursive_iterator;
    }//namespace

    Variant::Variant(const Variant& src):mHelper(),mData(){ operator=(src); }
    Variant::Variant(const bool     src):mHelper(),mData(){ operator=(src); }
    Variant::Variant(const char*    src):mHelper(),mData(){ operator=(src); }
    Variant::Variant(const wchar_t* src):mHelper(),mData(){ operator=(src); }
//---------------------------------------------------------------------------------------------
    Variant& Variant::operator= (const Variant& src)
    {
        mHelper = src.mHelper;
        mData   = src.mData;
        return *this;
    }

    Variant& Variant::operator= (const char* src)
    {
        mData = Str(src);  mHelper = variant_detail::Helper<Str>();
        return *this;
    }
    Variant& Variant::operator= (const wchar_t* src)
    {
        mData = WStr(src); mHelper = variant_detail::Helper<WStr>();
        return *this;
    }
//---------------------------------------------------------------------------------------------
    Variant::operator const char*()const
    {
        ThrowIfFalse( Is<Str>() );
        const Str& data = *mData.Resource<Str>();
        return data.c_str();
    }
    Variant::operator const wchar_t*()const
    {
        ThrowIfFalse( Is<WStr>() );
        const WStr& data = *mData.Resource<WStr>();
        return data.c_str();
    }
//---------------------------------------------------------------------------------------------
    bool Variant::operator == (const Variant& rhs)const
    {
        const size_t empty_this  = Empty()?     1: 0;
        const size_t empty_other = rhs.Empty()? 1: 0;
        if(empty_this + empty_other == 2)
            return true;
        if(empty_this != empty_other)
            return false;

        return mHelper->Compare(mData.Resource(), rhs.mData.Resource(), rhs.GetType());
    }
//---------------------------------------------------------------------------------------------
          Variant::Helper& Variant::GetHelper()      { return mHelper; }
    const Variant::Helper& Variant::GetHelper()const { return mHelper; }

          Variant::Data& Variant::GetData()          { return mData;   }
    const Variant::Data& Variant::GetData()const     { return mData;   }
//---------------------------------------------------------------------------------------------
    Variant::Str Variant::ToString()const
    {
        if(Empty())
            return Out<SEmpty>::ToString();
        return mHelper->ToString( mData.Resource<void>() );
    }
//---------------------------------------------------------------------------------------------
    Variant::Str Variant::ToHummanStyle()const
    {
        return ::tools::ToHummanStyle(*this);
    }
//---------------------------------------------------------------------------------------------
    size_t Variant::Elements()const
    {
        if(Empty())
            return 0;
        return mHelper->Elements( mData.Resource<void>() );
    }
//---------------------------------------------------------------------------------------------
    bool Variant::IsFloating()const
    {
        return mHelper.Empty()? false: mHelper->IsFloating();
    }
    bool Variant::IsInteger()const
    {
        return mHelper.Empty()? false: mHelper->IsInteger();
    }
//---------------------------------------------------------------------------------------------
    const ::std::type_info& Variant::GetTypeInfo()const
    {
        return mHelper.Empty()? typeid(void) : mHelper->GetTypeInfo();
    }
    //---------------------------------------------------------------------------------------------    
    const char* Variant::GetTypeName()const
    {
        return mHelper.Empty()? "NULL" : mHelper->GetTypeName();
    }
    //---------------------------------------------------------------------------------------------    
    Variant::eTYPE Variant::GetType()const { return mHelper.Empty()? eNULL : mHelper->GetType(); }

    Variant::eCATEGORY Variant::GetCategory()const
    {
        const bool ERROR_EMPTY_VARIANT = Empty();
            assert(!ERROR_EMPTY_VARIANT);
            if(ERROR_EMPTY_VARIANT)
                throw ::std::runtime_error("ERROR_EMPTY_VARIANT");

        return mHelper->GetCategory();
    }
    //---------------------------------------------------------------------------------------------    
    size_t Variant::SizeData()const
    {
        return mHelper.Empty()? 0 : mHelper->GetSize();
    }
    //---------------------------------------------------------------------------------------------    
    bool Variant::IsPrimitive()const { return  Empty() || mHelper->IsPrimitive();        }
    bool Variant::IsVector()const    { return !Empty() && mHelper->GetType() == eVECTOR; }
    bool Variant::IsBlob()const      { return !Empty() && mHelper->GetType() == eBLOB;   }
    bool Variant::IsMap()const       { return !Empty() && mHelper->GetType() == eMAP;    }
    bool Variant::IsList()const      { return !Empty() && mHelper->GetType() == eLIST;   }

//---------------------------------------------------------------------------------------------    
    void Variant::ThrowIfFalse(const bool valid)const
    {
        const bool ERROR_INVALID_TYPE = !valid;
            assert(!ERROR_INVALID_TYPE);
            if(ERROR_INVALID_TYPE)
                throw ::std::runtime_error("ERROR_INVALID_TYPE");
    }
//---------------------------------------------------------------------------------------------    
    void Variant::MakeMinsize()
    {
        if(Empty())
            return;

        eTYPE type = mHelper->GetType();

        #define ENUM_CASE(enum_type)                                     \
            case enum_type:                                              \
            {                                                            \
                typedef variant_detail::Enum2Type<enum_type>::Type Type; \
                const Type& data = *mData.Resource<Type>();              \
                *this = MakeMinsize(data);                               \
                return;                                                  \
            }

        switch (type)
        {
            case eBOOL: return;
            case eBYTE: return;
            ENUM_CASE(eF32)  ENUM_CASE(eF64)    
            ENUM_CASE(eI8)   ENUM_CASE(eI16)    ENUM_CASE(eI32)   ENUM_CASE(eI64)    
            ENUM_CASE(eU8)   ENUM_CASE(eU16)    ENUM_CASE(eU32)   ENUM_CASE(eU64)    
            default:
            {
                #ifdef DEBUG
                const bool ERROR_MOST_BE_INTEGER_OR_FLOATING = true;
                assert(!ERROR_MOST_BE_INTEGER_OR_FLOATING);
                #endif // DEBUG
                throw ::std::logic_error("ERROR_MOST_BE_INTEGER_OR_FLOATING");
            }

        }
        #undef ENUM_CASE
    }
//---------------------------------------------------------------------------------------------    
    Variant& Variant::operator[](const Str& key)
    {
        if(Empty())
            (*this)=Map();

        Map& mp = *this;
        return mp[key];
    }
    const Variant& Variant::operator[](const Str& key)const
    {
        const Map& mp = *this;
        Map::const_iterator it = mp.find(key);

        #ifdef DEBUG
        const bool ERROR_INVALID_KEY = it==mp.end();
        assert(!ERROR_INVALID_KEY);
        #endif // DEBUG
        
        return it->second;
    }
//---------------------------------------------------------------------------------------------    
    Variant& Variant::operator[](const size_t index)
    {
        if(Empty())
        {
            Vec& vec = operator=( Vec() ).AsVector();
            return vec.resize(index+1), AsVector().at(index);
        }
        else if( index == Elements() )
            Push();

        const bool ERROR_OUT_OF_RANGE = index >= Elements();
        assert(!ERROR_OUT_OF_RANGE);
        if(ERROR_OUT_OF_RANGE)
            throw ::std::out_of_range("ERROR_OUT_OF_RANGE");

        Vec& vec = *this;
        return vec.at(index);
    }
    const Variant& Variant::operator[](const size_t index)const
    {
        const Vec& vec = *this;
        return vec.at(index);
    }
//---------------------------------------------------------------------------------------------    
    Variant& Variant::operator[](const int index)
    {
        const bool ERROR_INDEX_SUB_ZERO = index<0;
        assert(!ERROR_INDEX_SUB_ZERO);
        if(ERROR_INDEX_SUB_ZERO)
            throw ::std::out_of_range("ERROR_INDEX_SUB_ZERO");
        return operator[]( static_cast<size_t>(index) );
    }
    const Variant& Variant::operator[](const int index)const
    {
        const bool ERROR_INDEX_SUB_ZERO = index<0;
        assert(!ERROR_INDEX_SUB_ZERO);
        if(ERROR_INDEX_SUB_ZERO)
            throw ::std::out_of_range("ERROR_INDEX_SUB_ZERO");

        return operator[]( static_cast<size_t>(index) );
    }
//---------------------------------------------------------------------------------------------    
    void Variant::Push()
    {
        const bool ERROR_MOST_BE_VECTOR = !Is<Vec>();
        assert(!ERROR_MOST_BE_VECTOR);
        if(ERROR_MOST_BE_VECTOR)
            throw ::std::logic_error("ERROR_MOST_BE_VECTOR");

        AsVector().emplace_back( Variant() );
    }
//---------------------------------------------------------------------------------------------    
    iterator               Variant::begin()              { return iterator(*this);                          }
    iterator               Variant::end()                { return iterator(*this, false);                   }
    const_iterator         Variant::begin()const         { return const_iterator(*this);                    }
    const_iterator         Variant::end()const           { return const_iterator(*this, false);             }
    const_iterator         Variant::cbegin()const        { return const_iterator(*this);                    }
    const_iterator         Variant::cend()const          { return const_iterator(*this, false);             }
    reverse_iterator       Variant::rbegin()             { return reverse_iterator(*this);                  }
    reverse_iterator       Variant::rend()               { return reverse_iterator(*this, false);           }
    const_reverse_iterator Variant::rbegin()const        { return const_reverse_iterator(*this);            }
    const_reverse_iterator Variant::rend()const          { return const_reverse_iterator(*this, false);     }
    const_reverse_iterator Variant::crbegin()const       { return const_reverse_iterator(*this);            }
    const_reverse_iterator Variant::crend()const         { return const_reverse_iterator(*this, false);     }

    recursive_iterator       Variant::recbegin()         { return recursive_iterator(*this);                }
    recursive_iterator       Variant::recend()           { return recursive_iterator(*this, false);         }
    const_recursive_iterator Variant::recbegin()const    { return const_recursive_iterator(*this);          }
    const_recursive_iterator Variant::recend()const      { return const_recursive_iterator(*this, false);   }
    const_recursive_iterator Variant::crecbegin()const   { return const_recursive_iterator(*this);          }
    const_recursive_iterator Variant::crecend()const     { return const_recursive_iterator(*this, false);   }


}//namespace tools

